package com.homedo.microservice.open.service.gateway.alert.task;


import com.google.common.collect.Lists;
import com.homedo.common.bean.vo.Order;
import com.homedo.common.bean.vo.Pagination;
import com.homedo.common.util.Detect;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.enums.forroute.StatusEnum4Route;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.enums.forrouteserviceurl.StatusEnum4RouteServiceUrl;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.HealthCheckingErrorStatistics;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.Route;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.RouteServiceUrl;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.enhanced.RouteEnhanced;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.enhanced.RouteServiceEnhanced;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.po.enhanced.RouteServiceUrlEnhanced;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.query.RouteQuery;
import com.homedo.microservice.open.service.gateway.alert.gateway.bean.query.RouteServiceUrlQuery;
import com.homedo.microservice.open.service.gateway.alert.gateway.service.HealthCheckingErrorStatisticsService;
import com.homedo.microservice.open.service.gateway.alert.gateway.service.RouteService;
import com.homedo.microservice.open.service.gateway.alert.gateway.service.RouteServiceService;
import com.homedo.microservice.open.service.gateway.alert.gateway.service.RouteServiceUrlService;
import com.netflix.config.DynamicIntProperty;
import com.netflix.config.DynamicPropertyFactory;
import com.netflix.config.DynamicStringProperty;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 健康的后端服务器检测
 */
@Component
public class HealthServerDetectTask {

    @Autowired
    private RouteServiceUrlService routeServiceUrlService;
    @Autowired
    private HealthCheckingErrorStatisticsService healthCheckingErrorStatisticsService;
    @Autowired
    private RouteService routeService;
    @Autowired
    private RouteServiceService routeServiceService;

    //检测应用
    private DynamicStringProperty applicationNames = DynamicPropertyFactory.getInstance().getStringProperty("alert.applicationNames", "");
    //多少时间内的统计有效
    private DynamicIntProperty errorStatisticsTimeIntervalSeconds = DynamicPropertyFactory.getInstance().getIntProperty("alert.errorStatisticsTimeIntervalSeconds", 180);

    private static final Logger LOGGER = LoggerFactory.getLogger(HealthServerDetectTask.class);

    @Scheduled(cron = "0/6 * * * * ?")
    public void task() {

        this.doSchedule();

    }

    private void doSchedule() {
        if (!Detect.notEmpty(applicationNames.get())) {
            return;
        }

        String[] applicationNameParts = applicationNames.get().split(",");
        for (String applicationNamePart : applicationNameParts) {
            this.dealServiceGateway(applicationNamePart.trim());
        }
    }

    private void dealServiceGateway(String applicationName) {
        //有效的路由 监控器地址
        Pagination<RouteEnhanced> routeEnhancedPagination = new Pagination<>(1, Integer.MAX_VALUE, false);
        routeEnhancedPagination.addOrder(new Order(Route.COLUMN_CREATE_TIME, Order.ORDER_DESC), Route.class);
        RouteQuery routeQuery = new RouteQuery();
        routeQuery.setStatuses(Lists.newArrayList(StatusEnum4Route.EFFECTIVE.getCode()));
        routeQuery.setApplicationNames(Lists.newArrayList(applicationName));

        routeEnhancedPagination = routeService.getPagination(routeQuery, routeEnhancedPagination, null);
        if (!Detect.notEmpty(routeEnhancedPagination.getItems())) {
            return;
        }

        List<String> serviceIds = routeEnhancedPagination.getItems().stream().map(RouteEnhanced::getRouteServiceEnhanced)
                .collect(Collectors.toList()).stream().map(RouteServiceEnhanced::getId).collect(Collectors.toList());

        //有效的服务组 监控地址
//        Pagination<RouteServiceEnhanced> routeServiceEnhancedPagination = new Pagination<>(1, Integer.MAX_VALUE, false);
//        routeServiceEnhancedPagination.addOrder(new Order(Route.COLUMN_CREATE_TIME, Order.ORDER_DESC), Route.class);
//        RouteServiceQuery routeServiceQuery = new RouteServiceQuery();
//        routeServiceQuery.setStatuses(Lists.newArrayList(StatusEnum4RouteService.EFFECTIVE.getCode()));
//        routeServiceQuery.setApplicationNames(Lists.newArrayList(applicationName));
//
//        routeServiceEnhancedPagination = routeServiceService.getPagination(routeServiceQuery, routeServiceEnhancedPagination, null);
//        if (!Detect.notEmpty(routeServiceEnhancedPagination.getItems())) {
//            return;
//        }
//
//        List<String> serviceIds = routeServiceEnhancedPagination.getItems().stream().map(RouteServiceEnhanced::getId).collect(Collectors.toList());


        Pagination<RouteServiceUrlEnhanced> pagination = new Pagination(1, Integer.MAX_VALUE, false);
        pagination.addOrder(new Order(RouteServiceUrl.COLUMN_CREATE_TIME, Order.ORDER_DESC), RouteServiceUrl.class);

        RouteServiceUrlQuery routeServiceUrlQuery = new RouteServiceUrlQuery();
        routeServiceUrlQuery.setStatuses(Lists.newArrayList(StatusEnum4RouteServiceUrl.EFFECTIVE.getCode()));
        routeServiceUrlQuery.setServiceIds(serviceIds);

        pagination = routeServiceUrlService.getPagination(routeServiceUrlQuery, pagination, null);
        if (!Detect.notEmpty(pagination.getItems())) {
            return;
        }

        pagination.setItems(routeServiceUrlService.appendEnhancedRouteService(pagination.getItems(), null));

        pagination.getItems().forEach(e -> {
            if (e.getRouteServiceEnhanced() != null && Detect.notEmpty(e.getRouteServiceEnhanced().getHealthUrl())) {
                String checkUrl = e.getUrl() + e.getRouteServiceEnhanced().getHealthUrl();
                if (!this.checkGet(checkUrl)) {
                    this.dealCheckFail(e);
                }
            }
        });

    }

    private void dealCheckFail(RouteServiceUrlEnhanced routeServiceUrlEnhanced) {
        HealthCheckingErrorStatistics record = new HealthCheckingErrorStatistics();
        record.setApplicationName(routeServiceUrlEnhanced.getRouteServiceEnhanced().getApplicationName());
        record.setServiceId(routeServiceUrlEnhanced.getRouteServiceEnhanced().getId());
        record.setUrl(routeServiceUrlEnhanced.getUrl());

        HealthCheckingErrorStatistics healthCheckingErrorStatistics = healthCheckingErrorStatisticsService.getOneByRecord(record, null);
        if (healthCheckingErrorStatistics == null) {
            record.setCount(1);
            record.setCreateTime(new Date());
            record.setUpdateTime(new Date());

            healthCheckingErrorStatisticsService.saveSelective(record, null);
        } else {
            HealthCheckingErrorStatistics updateRecord = new HealthCheckingErrorStatistics();
            updateRecord.setId(healthCheckingErrorStatistics.getId());
            updateRecord.setUpdateTime(new Date());
            int maxCount = 10000;
            int count = healthCheckingErrorStatistics.getCount();
            DateTime lastUpdateTime = new DateTime(healthCheckingErrorStatistics.getUpdateTime())
                    .plusSeconds(errorStatisticsTimeIntervalSeconds.get());

            if (lastUpdateTime.isAfterNow()) {//检查区间内
                if (count >= maxCount) {
                    count = maxCount;
                } else {
                    count += 1;
                }
            } else {//检查区间外
                count = 1;
            }

            updateRecord.setCount(count);

            healthCheckingErrorStatisticsService.updateByPrimaryKeySelective(updateRecord, null);
        }

    }


    public boolean checkGet(String url) {
        HttpGet httpGet = null;
        CloseableHttpResponse httpresponse = null;
        CloseableHttpClient client = HttpClients.createDefault();
        try {
            httpGet = new HttpGet(url);
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(6000).setConnectTimeout(4000).build();
            // 设置超时
            httpGet.setConfig(requestConfig);

            httpresponse = client.execute(httpGet);

            int statusCode = httpresponse.getStatusLine().getStatusCode();
            if (HttpStatus.SC_OK == statusCode) {
                return true;
            }
            return false;
        } catch (Exception ex) {
            LOGGER.warn("[检测后端健康服务,请求失败:{}--{}]", url, ex.getMessage());
            return false;
        } finally {
            if (httpresponse != null) {
                try {
                    httpresponse.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (httpGet != null && !httpGet.isAborted()) {
                httpGet.releaseConnection();
            }
            if (client != null) {
                try {
                    client.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
